package com.example.shuiyin.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Primary;

import java.time.Duration;
import java.util.concurrent.TimeUnit;

@Configuration
@Slf4j
public class RedisConfig {

    @Value("${spring.redis.host:localhost}")
    private String redisHost;
    
    @Value("${spring.redis.port:6379}")
    private int redisPort;
    
    @Value("${spring.redis.database:0}")
    private int redisDatabase;
    
    @Value("${spring.redis.timeout:5000}")
    private int timeout;
    
    @Bean
    @Primary
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        log.info("初始化Redis模板...");
        
        try {
            RedisTemplate<String, Object> template = new RedisTemplate<>();
            template.setConnectionFactory(connectionFactory);
            
            // 设置key的序列化方式
            template.setKeySerializer(new StringRedisSerializer());
            template.setHashKeySerializer(new StringRedisSerializer());
            
            // 设置value的序列化方式
            GenericJackson2JsonRedisSerializer jsonSerializer = new GenericJackson2JsonRedisSerializer();
            template.setValueSerializer(jsonSerializer);
            template.setHashValueSerializer(jsonSerializer);
            
            template.afterPropertiesSet();
            
            // 测试连接
            Boolean result = template.execute(connection -> {
                try {
                    return connection.ping() != null;
                } catch (Exception e) {
                    log.warn("Redis连接测试失败: {}", e.getMessage());
                    return false;
                }
            }, true);
            
            if (result != null && result) {
                log.info("Redis连接测试成功: {}:{}/{}", redisHost, redisPort, redisDatabase);
            } else {
                log.warn("Redis连接测试失败，但将继续使用本地缓存替代");
            }
            
            return template;
        } catch (Exception e) {
            log.error("Redis模板初始化失败: {}", e.getMessage(), e);
            log.warn("将使用应急Redis模板");
            
            // 创建一个应急的Redis模板，不依赖实际的Redis服务
            RedisTemplate<String, Object> fallbackTemplate = new RedisTemplate<>();
            fallbackTemplate.setConnectionFactory(connectionFactory);
            fallbackTemplate.setKeySerializer(new StringRedisSerializer());
            fallbackTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
            try {
                fallbackTemplate.afterPropertiesSet();
            } catch (Exception ex) {
                log.error("应急Redis模板初始化也失败: {}", ex.getMessage());
            }
            
            return fallbackTemplate;
        }
    }
    
    /**
     * 检测Redis服务是否可用
     */
    public boolean isRedisAvailable() {
        try {
            RedisTemplate<String, Object> template = redisTemplate(
                new LettuceConnectionFactory(new RedisStandaloneConfiguration(redisHost, redisPort)));
            
            return template.execute(connection -> {
                try {
                    return connection.ping() != null;
                } catch (Exception e) {
                    return false;
                }
            }, true);
        } catch (Exception e) {
            return false;
        }
    }
} 